<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width,user-scalable=no"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="keywords" content="spring-oauth-server,OIDC1.0,OAuth2.1,IAM,IDaaS,WebAuthn"/>
    <meta name="description" content="spring-oauth-server,OIDC1.0,OAuth2.1,IAM,IDaaS,WebAuthn,MKK,monkeyk7,security"/>
    <meta name="author" content="andaily.com"/>
    <link rel="shortcut icon" href="../static/favicon.ico" th:href="@{/favicon.ico}"/>

    <title>refresh_token . spring-oauth-client</title>

    <th:block th:insert="~{fragments/main::header-css}"/>
</head>
<body ng-app>
<div class="container">
    <a th:href="@{/}">Home</a>

    <h2>refresh_token</h2>

    <div>
        grant_type = 'refresh_token' 模式用在当获取的access_token未过期之前向服务端换取新的access_token.
        <br/>
        在获取access_token时返回的数据如下
        <pre>{
  "access_token": "7154afT_cxvLDq1naSg6Aq9ueSFSW8xRr5txryW5MlddRe7nV0RogTYwPsJc_rrRqwaIvLleerLhkjtIN2E2U-...",
  "refresh_token": "TZ9tzVwE_VLoJxALUSw4A4A0Nj7SLSWXCc69U9rvNmSnqR8Hbz-...",
  "scope": "openid profile",
  "id_token": "eyJraWQiOiJzb3MtZWNjLWtpZDEiLCJhbGciOiJFUzI1NiJ9..3w-7EY9SwKA-...",
  "token_type": "Bearer",
  "expires_in": 3599
}</pre>
        <p>
            数据中的<code>expires_in</code>即access_token的有效时间(单位:秒), 在服务端可配置client的access_token有效时间.
        </p>

        <p>
            数据中<code>refresh_token</code>的值将用于换取新的access_token.
            <br/>
            <strong>注意</strong> refresh_token 成功后旧的access_token将不能再使用.
        </p>
        <small class="text-muted">
            <em class="glyphicon glyphicon-info-sign"></em> 在实际应用中, refresh_token一般都是由后台来完成的,前台没有任何表现.
        </small>
    </div>

    <hr/>
    <div ng-controller="RefreshTokenCtrl">
        <div class="panel panel-default">
            <div class="panel-heading"><em>调用 grant_type='refresh_token' 去换取新的access_token</em></div>
            <div class="panel-body">
                <form class="form-horizontal" action="#" onsubmit="return false;">
                    <div class="form-group">
                        <label class="col-sm-2 control-label">refreshTokenUri</label>

                        <div class="col-sm-10">
                            <p class="form-control-static"><code>[[${accessTokenUri}]]</code>
                                &nbsp;<a th:href="${accessTokenUri}" target="_blank">测试连接</a></p>
                        </div>
                    </div>
                    <a href="javascript:void(0);" ng-click="showTokenParams()">显示请求参数</a>

                    <div ng-show="tokenParamVisible">

                        <div class="form-group">
                            <label class="col-sm-2 control-label">client_id</label>

                            <div class="col-sm-10">
                                <input type="text" class="form-control" name="client_id" required="required"
                                       ng-model="clientId"/>

                                <p class="help-block">客户端从 spring-oauth-server 申请的client_id, 有的Oauth服务器中又叫 AppKey</p>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">client_secret</label>

                            <div class="col-sm-10">
                                <input type="text" class="form-control" name="client_secret" required="required"
                                       ng-model="clientSecret"/>

                                <p class="help-block">客户端从 spring-oauth-server 申请的client_secret, 有的Oauth服务器中又叫
                                    AppSecret</p>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">grant_type</label>

                            <div class="col-sm-10">
                                <input type="text" class="form-control" name="grant_type" readonly="readonly"
                                       ng-model="refreshGrantType"/>

                                <p class="help-block">固定值 'refresh_token'</p>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">refresh_token</label>

                            <div class="col-sm-10">
                                <input type="text" class="form-control" name="refresh_token"
                                       placeholder="请先填写refresh_token" id="refreshTokenId"
                                       ng-model="refreshToken"/>

                                <p class="help-block">从 spring-oauth-server 获取的 'refresh_token'</p>
                            </div>
                        </div>

                    </div>
                    <div class="alert alert-info">提示: 若client关闭了复用refresh_token功能(默认开启),
                        则每次请求后会响应一个新的refresh_token值(即一个refresh_token只能使用一次, 安全性更高).
                    </div>
                    <br/>
                    <button class="btn btn-info" ng-click="executeRefreshToken()">刷新access_token</button>
                    <span class="label label-warning">POST</span>
                </form>

                <div ng-show="refreshTokenVisible">
                    <hr/>
                    刷新后的access_token信息
                    <div class="well well-sm">
                        <dl class="dl-horizontal">
                            <dt>access_token</dt>
                            <dd><textarea rows="5" readonly class="form-control">{{newAccessToken}}</textarea></dd>
                            <dt>token_type</dt>
                            <dd><code>{{newTokenType}}</code></dd>
                            <dt>refresh_token</dt>
                            <dd><textarea rows="2" readonly class="form-control">{{newRefreshToken}}</textarea></dd>
                            <dt>scope</dt>
                            <dd><code>{{newTokenScope}}</code></dd>
                            <dt>expires_in</dt>
                            <dd><code>{{newExpiresIn}}</code></dd>
                        </dl>
                        <p class="text-danger">{{newTokenError}}</p>
                    </div>
                </div>
            </div>
        </div>

        <div class="text-center">
            <a href="javascript:history.back();" class="btn btn-default">返回</a>
        </div>
    </div>
</div>

<script th:inline="javascript">
    var RefreshTokenCtrl = ['$scope', '$http', function ($scope, $http) {
        $scope.accessTokenUri = [[${accessTokenUri}]];
        $scope.clientId = [[${clientDetails.clientId}]];
        $scope.clientSecret = [[${clientDetails.clientSecret}]];

        $scope.scope = [[${clientDetails.scopes}]];
        $scope.refreshToken = "";
        $scope.refreshGrantType = "refresh_token";

        $scope.tokenParamVisible = true;
        $scope.refreshTokenVisible = false;


        $scope.executeRefreshToken = function () {
            if ($scope.refreshToken === "") {
                document.getElementById("refreshTokenId").focus();
                return;
            }

            var uri = "refresh_access_token?clientId=" + $scope.clientId + "&clientSecret=" + $scope.clientSecret + "&grantType=" + $scope.refreshGrantType
                + "&refreshToken=" + $scope.refreshToken + "&refreshAccessTokenUri=" + encodeURIComponent($scope.accessTokenUri);

            $http.get(uri).success(function (data) {
                $scope.newAccessToken = data.accessToken;
                $scope.newTokenType = data.tokenType;
                $scope.newRefreshToken = data.refreshToken;

                $scope.newTokenScope = data.scope;
                $scope.newExpiresIn = data.expiresIn;
                //if have error
                $scope.newTokenError = data.error + " " + data.errorDescription;

                $scope.refreshTokenVisible = true;
            });
        };
    }];
</script>

<div th:replace="~{fragments/main :: footer}"/>
</div>
</body>
</html>